/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package flightlifter;

import GUI.Button;
import GUI.GUILayout;
import java.util.Vector;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;

/**
 *
 * @author Matt
 */
public class Wing extends Node {

    Point a, b, c, d;
    PVector lastCentroid = new PVector();
    PVector centroid = new PVector();
    PVector dir = new PVector();
    PVector norm = new PVector();
    PVector norm2 = new PVector();
    PVector ncop;
    float vel;
    float area;
    boolean stalled = false;
    Texture wingTexture;
    int shaderProgram;
    float u0 = 0, u1 = 1.f;
    float v0 = 0, v1 = 1.f;
    private Button AoA, ClButton, CdButton, liftButton, areaButton, velButton;

    public Wing(Point a, Point b, Point c, Point d, Texture tex, int shaderProgram) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;

        //this prevents loaded models from having energey
        lastCentroid = getCentroid();
        centroid = getCentroid();
        //need a normal for rendering
        PVector.cross(PVector.sub(a.pos, b.pos), PVector.sub(c.pos, b.pos), norm);

        wingTexture = tex;
        this.shaderProgram = shaderProgram;

        AoA = new Button("AoA: ", null);
        ClButton = new Button("Cl: ", null);
        CdButton = new Button("Cd: ", null);
        liftButton = new Button("Lift: ", null);
        areaButton = new Button("Area: ", null);
        velButton = new Button("Velocity: ", null);
    }

    public void populateInfoBox(GUILayout layout) {
        layout.add(AoA);
        layout.add(ClButton);
        layout.add(CdButton);
        layout.add(liftButton);
        layout.add(areaButton);
        layout.add(velButton);

    }

    public void physics() {

        centroid = getCentroid();

        PVector leadingEdge = PVector.sub(b.pos, a.pos);
        PVector forward = PVector.sub(a.pos, a.lastPos);
        PVector up = new PVector();

        leadingEdge.normalize();

        vel = forward.mag();

        //this will normalize the forward vector
        //we needs its magnitude for later
        forward.div(vel);

        //convert vel to m/s
        vel *= (float) FlightLifter.FRAMERATE;

        //lift is not the wing normal -- it is perpendicular to the freestream flow
        PVector.cross(forward, leadingEdge, up);

        //get the area of the first triangle
        PVector.cross(PVector.sub(a.pos, b.pos), PVector.sub(c.pos, b.pos), norm);
        area = .5f * norm.mag();

        //add area of second triangle to get full planar area of wing
        PVector.cross(PVector.sub(c.pos, d.pos), PVector.sub(a.pos, d.pos), norm2);
        area += .5f * norm2.mag();

        areaButton.title = "Area: " + area + "m^2";

        norm.normalize();
        norm2.normalize();

        //average the normals and use them to find the angle of attack
        PVector.add(norm, norm2, norm);
        PVector.div(norm, 2);
        float aoa = PVector.angleBetween(norm, forward);


        aoa -= Math.PI / 2.f;

        velButton.title = "Velocity: " + vel + "m/s";

        AoA.title = "AoA: " + aoa;

        float Cl = getLiftCoefficient(aoa);
        float Cd = getDragCoefficient(aoa);

        ClButton.title = "Cl: " + Cl;
        CdButton.title = "Cd: " + Cd;

        float p = 1.229f / 300; //kg/m^3 at STP

        float lift = p * Cl * (vel * vel) * area / 2;

        liftButton.title = "Lift: " + (lift) + "N";

        float span = PVector.sub(b.pos, a.pos).mag();
        float aspectRatio = (span * span) / area;


        float e = .7f;
        //induced drag http://www.grc.nasa.gov/WWW/K-12/airplane/dragco.html
        float Ci = (Cl * Cl) / (3.14159f * aspectRatio * e);

        float drag = p * (Cd + Ci) * (vel * vel) * area / 2;

        //apply the lift
        norm.mult(lift);

        ncop = norm.get();
        ncop.mult(1 / 4.f);
        a.impulse(ncop);

        ncop = norm.get();
        ncop.mult(1 / 4.f);
        b.impulse(ncop);

        ncop = norm.get();
        ncop.mult(1 / 4.f);
        c.impulse(ncop);

        ncop = norm.get();
        ncop.mult(1 / 4.f);
        d.impulse(ncop);

        //apply the drag
        dir.mult(-drag);

        ncop = dir.get();
        a.impulse(ncop);

        ncop = dir.get();
        b.impulse(ncop);

        ncop = dir.get();
        c.impulse(ncop);

        ncop = dir.get();
        d.impulse(ncop);


        dir.mult(Cd);
        norm.mult(Cl);





    }

    public void render(int mode) {

        float alpha;

        if (mode == FlightLifter.QUAD_RENDER){
            alpha = .25f;
            GL11.glDisable(GL11.GL_DEPTH_TEST);
        }
        else alpha = 1.f;

        if (selected == 1) {
            GL11.glColor4f(1.0f, 1.0f, 1.0f,alpha);
        } else {
            GL11.glColor4f(1f, 1f, 1f,alpha);
        }

        norm.normalize();

        //wingTexture.bind();

        GL11.glBegin(GL11.GL_QUADS);                    // Drawing Using Triangles

        GL11.glNormal3f(norm.x, norm.y, norm.z);
        GL11.glTexCoord2f(u0, v1);
        GL11.glVertex3f(d.pos.x, d.pos.y, d.pos.z);

        GL11.glNormal3f(norm.x, norm.y, norm.z);
        GL11.glTexCoord2f(u1, v1);
        GL11.glVertex3f(c.pos.x, c.pos.y, c.pos.z);

        GL11.glNormal3f(norm.x, norm.y, norm.z);
        GL11.glTexCoord2f(u1, v0);
        GL11.glVertex3f(b.pos.x, b.pos.y, b.pos.z);

        GL11.glNormal3f(norm.x, norm.y, norm.z);
        GL11.glTexCoord2f(u0, v0);
        GL11.glVertex3f(a.pos.x, a.pos.y, a.pos.z);

        GL11.glEnd();

       // GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        //GL11.glDisable(GL11.GL_TEXTURE_2D);

        /*
        //draw direction
        GL11.glColor3f(1.0f, 1.0f, 1.f);
        GL11.glBegin(GL11.GL_LINES);
        GL11.glVertex3f(centroid.x, centroid.y, centroid.z);
        GL11.glVertex3f(centroid.x + dir.x, centroid.y + dir.y, centroid.z + dir.z);
        GL11.glEnd();

        //draw normal
        GL11.glColor3f(.5f, 1.0f, .5f);
        GL11.glBegin(GL11.GL_LINES);
        GL11.glVertex3f(centroid.x, centroid.y, centroid.z);
        GL11.glVertex3f(centroid.x + norm.x, centroid.y + norm.y, centroid.z + norm.z);
        GL11.glEnd();
         */
        GL11.glEnable(GL11.GL_DEPTH_TEST);

    }

    public PVector getCentroid() {
        return new PVector((a.pos.x + b.pos.x + c.pos.x + d.pos.x) / 4.f,
                (a.pos.y + b.pos.y + c.pos.y + d.pos.y) / 4.f,
                (a.pos.z + b.pos.z + c.pos.z + d.pos.z) / 4.f);
    }

    public PVector getScreenSpaceCentroid() {
        float[] ret = GLProject.project((a.pos.x + b.pos.x + c.pos.x + d.pos.x) / 4.f,
                (a.pos.y + b.pos.y + c.pos.y + d.pos.y) / 4.f,
                (a.pos.z + b.pos.z + c.pos.z + d.pos.z) / 4.f);

        return new PVector(ret[0], ret[1], 0);
    }

    public Wing(String[] line, Vector<Node> nodes, Texture tex, int shaderProgram) {
        this((Point) nodes.elementAt(Integer.parseInt(line[1])),
                (Point) nodes.elementAt(Integer.parseInt(line[2])),
                (Point) nodes.elementAt(Integer.parseInt(line[3])),
                (Point) nodes.elementAt(Integer.parseInt(line[4])),
                tex, shaderProgram);
    }

    public String pickle(Vector<Node> nodes) {
        return "W,"
                + nodes.indexOf(a) + ","
                + nodes.indexOf(b) + ","
                + nodes.indexOf(c) + ","
                + nodes.indexOf(d) + ",";
    }

    public void moveTexture(float dx, float dy) {
        u0 += dx;
        u1 += dx;
        v0 += dy;
        v1 += dy;

    }

    private float getLiftCoefficient(float aoa) {
        return (1.15f * (float) Math.sin(2 * aoa));
    }

    private float getDragCoefficient(float aoa) {
        return (1.8f * (float) Math.sin(aoa));

    }

    public boolean dependsOn(Point p) {
        if (p == a || p == b || p == c || p == d) {
            return true;
        } else {
            return false;
        }
    }
}
